home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1987
- * Louis A. Mamakos WA3YMH
- * All rights reserved.
- *
- * This code may not be redistributed, sold, included on any collection of
- * software which is sold. Use of this software is restricted to inclusion
- * in the KA9Q TCP/IP software package for use on a Commodore-Amiga system.
- * Commercial use is prohibited. Only educational and Amateur Packet Radio
- * use is allowed.
- */
-
- #ifdef AMIGADEVDRV
- /*
- * This module is the meat of the Amiga 'internet.device' device driver. There
- * are assembly language stubs in devstub.asm that call this module when user
- * program access the device driver. Remember: the tasks running this code are
- * not our own!
- */
-
- #include <stdio.h>
-
- /* Amiga system definitions */
-
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/tasks.h>
- #include <exec/ports.h>
- #include <exec/libraries.h>
- #include <exec/io.h>
- #include <exec/devices.h>
- #include <exec/errors.h>
-
-
- /* get definitions of KA9Q TCP/IP protocol stuff... */
-
- #include "machdep.h"
- #include "timer.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "internet.h"
- #include "icmp.h"
- #include "ip.h"
- #include "tcp.h"
- #include "trace.h"
- #include "session.h"
- /* device driver specific definitions */
- #define ListEmpty(x) (! ((x)->lh_Head->ln_Succ))
-
- #include "inetdev.h"
- #ifdef TRACE
- #define tracedev(x) \
- if (trace & TRACE_DEVICE) printf(x)
-
- #define tracedev2(x,y) \
- if (trace & TRACE_DEVICE) printf(x,y)
-
- #define tracedev3(x,y,z) \
- if (trace & TRACE_DEVICE) printf(x,y,z)
-
- #define tracedev4(x,y,z,zz) \
- if (trace & TRACE_DEVICE) printf(x,y,z,zz)
- #endif
- char *malloc();
-
- extern void DSClose(), DSBeginIO(), DSAbortIO();
- extern struct InternetBase *DSOpen();
- extern long DSExpunge();
-
- void indev_tcp_r_upcall(), indev_tcp_t_upcall(), indev_s_upcall();
- struct SignalSemaphore INLock;
- struct Library *MakeLibrary();
-
- /* for open requests */
- int nopens; /* from iface */
- struct IOINETReq *iob = NULL;
- int unit_spec;
- struct InternetBase * dev;
- int OpenIt = 0,
- CN1 = 0,
- IOpenedIt = 0;
-
- extern int DeviceSignal;
- extern struct Process *mytask;
-
- printlist(l)
- struct List *l;
- {
- printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail,
- l->lh_TailPred);
- }
- /*
- * Initialize and install the Amiga 'internet.device'.
- */
- void
- DriverInit()
- {
- char *foo[10];
- int success;
- static int WeWereHere;
- int x;
- tracedev("DriverInit");
- x = WeWereHere;
- WeWereHere = 1;
- if (x)
- {
- printf("you tried to add the driver twice!!!\n");
- return;
- }
- foo[0] = (char *) &DSOpen;
- foo[1] = (char *) &DSClose;
- foo[2] = (char *) &DSExpunge;
- foo[3] = (char *) NULL;
- foo[4] = (char *) &DSBeginIO;
- foo[5] = (char *) &DSAbortIO;
- /* add any other custom routines here */
- foo[6] = (char *) -1;
-
- InternetBase = (struct InternetBase *)
- MakeLibrary(&foo[0], (char *) NULL, (char *) NULL,
- (long) sizeof(struct InternetBase), (char *) NULL);
-
- if (InternetBase == (struct InternetBase *) 0) {
- /* display alert? */
- return;
- }
-
- InitSemaphore(&(INLock));
- ObtainSemaphore(&(INLock));
- InitSemaphore(&(InternetBase->ib_lock));
- InternetBase->ib_lock.ss_Link.ln_Pri = 0;
- InternetBase->ib_lock.ss_Link.ln_Name = "internet.device lock";
-
- NewList(&InternetBase->ib_Units);
- InternetBase->ib_Units.lh_Type = NT_UNKNOWN;
-
- InternetBase->lib.lib_Node.ln_Type = NT_DEVICE;
- InternetBase->lib.lib_Node.ln_Pri = 0;
- InternetBase->lib.lib_Node.ln_Name = "internet.device";
- InternetBase->lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
- InternetBase->lib.lib_Version = IN_VERSION;
- InternetBase->lib.lib_Revision = IN_REVISION;
- InternetBase->lib.lib_IdString =
- (APTR) "internet.device 23 May 1987\r\n";
-
- success = AddDevice(InternetBase);
- Savea4();
- OpenIt = 0;
- IOpenedIt = 0;
- nopens = 1;
- CN1 = 5;
- if (success != 0)
- myoserr("driver open");
- printf("driver added returned %d\n",success);
-
- }
-
- void
- DriverShutdown()
- {
- long error;
- extern long *RemoveDevice();
-
- if (!InternetBase)
- return;
-
- if (error = RemDevice(InternetBase))
- printf("Can't remove device: error %ld\n", error);
-
- }
-
- struct InternetBase *
- NetDevOpen(mdev, munit_spec, miob, mflags)
- struct InternetBase *mdev;
- struct IOINETReq *miob;
- ULONG munit_spec, mflags;
- {
-
- iob = miob;
- dev = mdev;
- unit_spec = munit_spec;
-
- if (IOpenedIt == 1)
- {
- CN1++;
- return NULL;
- }
- OpenIt = 1;
- Permit();
- while (IOpenedIt == 0);
- Forbid();
- IOpenedIt = 0;
- return dev;
- }
- check_driver()
- {
- register struct INET_Unit *unit;
- register struct tcb *tcb;
- if (OpenIt != 0)
- {
-
- printf("open request!\n");
-
- switch (unit_spec) {
- case INET_UNIT_TCP:
- case INET_UNIT_UDP:
- break;
- default:
- iob->io_Error = IOERR_OPENFAIL;
- iob->io_Device = NULL;
- iob->io_Unit = NULL;
- OpenIt = 0;
- IOpenedIt = 1;
- goto doneopen;
- }
-
- if ((unit = (struct INET_Unit *)
- malloc(sizeof(struct INET_Unit))) == NULL) {
- iob->io_Error = IOERR_OPENFAIL;
- OpenIt = 0;
- IOpenedIt = 1;
- goto doneopen;
- }
- tracedev2("malloc ok %x\n", unit);
- iob->io_Unit = unit;
- iob->io_Device = (struct Device *)dev;
- dev->lib.lib_OpenCnt++;
-
- unit->iu_Unit.ln_Type = NT_UNKNOWN;
- unit->iu_Unit.ln_Pri = 0;
-
- NewList(&unit->iu_Input);
- NewList(&unit->iu_Output);
- printf("newlist ok\n");
- unit->iu_Input.lh_Type = NT_UNKNOWN; /* gee, what do we really */
- unit->iu_Output.lh_Type = NT_UNKNOWN; /* call these... */
- unit->iu_user = iob->io_Offset; /* always returned in Offset */
- unit->iu_Act_Input = NULL;
- unit->iu_Act_Output = NULL;
- iob->io_lsocket.address = ip_addr;
- iob->io_lsocket.port = lport++;
- AddTail(&InternetBase->ib_Units, &unit->iu_Unit);
- /* perform protocol specific open functions */
- printf("addtail\n");
-
- switch (unit_spec) {
- case INET_UNIT_TCP:
- /* Forbid(); */
- tcb = open_tcp(&(iob->io_lsocket), &(iob->io_fsocket),
- (USHORT) iob->io_Offset, (USHORT) iob->io_TCP_Window,
- indev_tcp_r_upcall, indev_tcp_t_upcall, indev_s_upcall,
- iob->io_INET_TOS, (char *)unit);
-
- /* Permit();*/
- if (tcb == NULL)
- goto fail;
- unit->iu_Unit.ln_Name = "TCP Connection";
- unit->iu_type = INET_UNIT_TCP;
- unit->iu_ccb = tcb;
- printf("cpopen is %d\n", tcb);
- break;
-
- default:
- fail:
- iob->io_Error = IOERR_OPENFAIL;
- dev->lib.lib_OpenCnt--;
- Remove(unit);
- free(unit);
- OpenIt = 0;
- IOpenedIt = 1;
- goto doneopen;
- }
- tracedev2("dev is %d\n", dev);
- OpenIt = 0;
- IOpenedIt = 1;
- }
- doneopen:
- /* spin until that other guy is all done. We will not get through
- * this spin until the other guy has done a Forbid() and
- * then a Permit(), since the IopenedIt gets cleared
- * AFTER the Forbid(). Sorry i do not use semaphores but
- * i do not have 1.2 autodocs so am not totally up on their
- * use.
- */
- while (IOpenedIt);
- }
- CheckTcp()
- {
- struct Node *head = InternetBase->ib_Units.lh_Head;
-
- struct INET_Unit *unit = (struct INET_Unit *) head;
- struct tcb *tcb;
- /* let the other guys in */
- ReleaseSemaphore(&(INLock));
- eihalt();
- ObtainSemaphore(&(INLock));
- tracedev("start checktcp\n");
- tracedev4("heda %x Pred is %x Succ is %x\n", head,head->ln_Pred, head->ln_Succ);
- for (;unit->iu_Unit.ln_Succ;unit = unit->iu_Unit.ln_Succ)
- {
- tracedev3("checktcp: %x Succ %d\n", unit, unit->iu_Unit.ln_Succ);
- if (unit->iu_type != INET_UNIT_TCP)
- {
- tracedev("not a tcp\n");
- continue;
- }
- tcb = (struct tcb *) unit->iu_ccb;
- if (tcb == NULL)
- {
- tracedev("NULL tcb in unit\n");
- continue;
- }
- if (tcb->state == ESTABLISHED)
- {
- tracedev("unit state is established!\n");
- /* continue;*/
- }
- tracedev("do the upcall\n");
- do_tupcall(tcb, 512); /* for now- it wil do the right thing */
- if (tcb->rcvcnt > 0)
- do_rupcall(tcb, tcb->rcvcnt);
- }
- tracedev("done checktcp\n");
- /* ReleaseSemaphore(&(INLock));*/
- }
- void DevClose(dev, iob)
- struct InternetBase *dev;
- struct IOINETReq *iob;
- {
- register struct INET_Unit *unit;
- struct tcb *tcb;
-
- unit = iob->io_Unit;
- tcb = unit->iu_ccb;
- del_tcp(tcb);
- Remove(unit);
- free(unit);
- iob->io_Unit = NULL;
-
- iob->io_Device = (struct Device *)dev;
- dev->lib.lib_OpenCnt--;
-
- /* remove iu_Unit from ib_Units list */
- /* decrement library use count */
- /* free unit structure */
- /* delete TCP/UDP connection del_tcp()/del_udp() */
- }
-
- long DevExpunge(dev)
- struct InternetBase *dev;
- {
- register char *m;
- register long len;
-
-
- if (InternetBase->lib.lib_OpenCnt) {
- InternetBase->lib.lib_Flags |= LIBF_DELEXP;
- return 0;
- }
- Remove(InternetBase); /* remove from library list */
- len = InternetBase->lib.lib_NegSize + InternetBase->lib.lib_PosSize;
- m = (char *) ((ULONG)InternetBase - InternetBase->lib.lib_NegSize);
- FreeMem(m, len);
- return 0;
- }
-
- #define C_IMMED (1<<0)
- #define C_READ (1<<1)
- #define C_WRITE (1<<2)
- void cmd_Invalid(), cmd_Reset(), cmd_Read(), cmd_Write(), cmd_Update(),
- cmd_Clear(), cmd_Stop(), cmd_Start(), cmd_Flush(), PerformIO();
-
- struct Commands {
- void (*cmd_func)();
- int cmd_flags;
- } commands [] = {
- { cmd_Invalid, C_IMMED }, /* invalid */
- { cmd_Reset, C_IMMED }, /* CMD_RESET */
- { cmd_Read, C_READ }, /* CMD_READ */
- { cmd_Write, C_WRITE }, /* CMD_WRITE */
- { cmd_Update, C_WRITE }, /* CMD_UPDATE */
- { cmd_Clear, C_IMMED }, /* CMD_CLEAR */
- { cmd_Stop, C_IMMED }, /* CMD_STOP */
- { cmd_Start, C_IMMED }, /* CMD_START */
- { cmd_Flush, C_IMMED }, /* CMD_FLUSH */
- };
-
- /* define last valid command */
- #define MAX_IO_COMMAND CMD_FLUSH
-
-
- /* BeginIO is called to begin processing of the I/O request */
-
- void DevBeginIO(iob, dev)
- struct IOINETReq *iob;
- struct InternetBase *dev;
- {
- register struct Commands *cmd;
- register struct INET_Unit *unit = iob->io_Unit;
- ObtainSemaphore(&(INLock));
- if (iob->io_Command > MAX_IO_COMMAND) {
- cmd_Invalid(iob, iob->io_Unit);
- goto done;
- }
- tracedev("io. ObtainSme\n");
-
- tracedev("got it\n");
- cmd = &commands[iob->io_Command];
- tracedev2("cmd is %d\n",iob->io_Command);
- tracedev2("flags %d\n", iob->io_Flags);
- if ((cmd->cmd_flags & C_IMMED) == 0) {
-
- /*
- * Code for commands which can queue
- */
-
- if ((cmd->cmd_flags & C_READ)/* && (unit->iu_Act_Input)*/) {
- AddTail(&unit->iu_Input, iob);
- iob->io_Flags &= ~IOF_QUICK;
- iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
- tracedev3("added %d to read queue of unit %d\n", iob, unit);
- goto done;
- }
-
- if ((cmd->cmd_flags & C_WRITE)/* && (unit->iu_Act_Output)*/) {
- AddTail(&unit->iu_Output, iob);
- iob->io_Flags &= ~IOF_QUICK;
- iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
- tracedev3("added %d to write queue of unit %d\n", iob, unit);
- goto done;
- }
- }
- PerformIO(iob, unit);
- done: tracedev4("flags QUI %x ~QUI %x %d\n", IOF_QUICK, ~IOF_QUICK,
- iob->io_Flags);
- Signal(mytask, DeviceSignal);
- ReleaseSemaphore(&(INLock));
- }
-
- void DevAbortIO(iob, dev)
- struct IOINETReq *iob;
- struct InternetBase *dev;
- {
- printf("DevAbortIo\n");
- }
-
- void
- PerformIO(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = 0;
- iob->io_Actual = 0;
- (*commands[iob->io_Command].cmd_func)(iob, unit);
- }
-
- void
- TermIO(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- struct tcb *tcb;
- tcb = (struct tcb *) unit->iu_ccb;
- iob->io_OldState = iob->io_State;
- iob->io_State = tcb->state;
- if ((iob->io_Flags & IOF_QUICK) == 0)
- /* not quick I/O */
- ReplyMsg(&iob->io_Message);
- }
-
- void
- cmd_Invalid(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
- void
- cmd_Reset(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
- void
- cmd_Read(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
- void
- cmd_Write(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
- void
- cmd_Update(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
- void
- cmd_Clear(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
-
- void
- cmd_Stop(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
-
- void
- cmd_Start(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
-
- void
- cmd_Flush(iob, unit)
- struct IOINETReq *iob;
- struct INET_Unit *unit;
- {
- iob->io_Error = IOERR_NOCMD;
- TermIO(iob, unit);
- }
-
-
- /* TCP receiver upcall routine. Called with TCB pointer and number of bytes
- available */
-
-
- do_rupcall(tcb, cnt)
- struct tcb *tcb;
- int16 cnt;
- {
- struct mbuf *bp;
- register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
- int amount, recamount;
- struct IOINETReq *iob;
- /* ObtainSemaphore(&(INLock));*/
- if (ListEmpty(&(unit->iu_Input)))
- goto done;
- iob = unit->iu_Act_Input = unit->iu_Input.lh_Head;
- tracedev4("dev rupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
- if (iob != NULL)
- {
- Remove(iob);
- amount = min(cnt, iob->io_Length);
- tracedev3("call recv_tcp %d bytes avail %d\n", amount, cnt);
- recamount = recv_tcp(tcb, &bp, amount);
- iob->io_Actual = dqdata(bp, iob->io_Data, recamount);
- tracedev2("recv_tcp after got %d bytes\n", iob->io_Actual);
- TermIO(iob, unit);
- /* ReplyMsg(&(iob->io_Message));*/
- }
- done:
- /* ReleaseSemaphore(&(INLock)); */
- }
- /* TCP receiver upcall routine. Called with TCB pointer and number of bytes
- available */
-
- void
- indev_tcp_r_upcall(tcb, cnt)
- struct tcb *tcb;
- int16 cnt;
- {
- /* ObtainSemaphore(&(INLock));*/
- do_rupcall(tcb, 512);
- /* ReleaseSemaphore(&(INLock)); */
- }
-
- /* TCP transmitter upcall routine. Called with TCB pointer and number of bytes
- free in send window */
-
-
- do_tupcall(tcb, avail)
- struct tcb *tcb;
- int16 avail;
- {
- struct mbuf *bp, *qdata();
- register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
- int amount;
- struct IOINETReq *iob;
-
- if (ListEmpty(&(unit->iu_Output)))
- goto done;
- tracedev("non-empty Output\n");
- iob = unit->iu_Act_Output = unit->iu_Output.lh_Head;
- tracedev4("dev tupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
- if (iob != NULL)
- {
- Remove(iob);
-
- amount = min(avail, iob->io_Length);
- tracedev3("t_upcall- send_tcp for addr %x %d bytes\n",iob->io_Data,
- amount);
- bp = qdata(iob->io_Data, amount);
- iob->io_Actual = send_tcp(tcb, bp);
- tracedev2("send_tcp after got %d bytes\n", iob->io_Actual);
- TermIO(iob, unit);
- /* ReplyMsg(&(iob->io_Message));*/
- unit->iu_Act_Output = NULL;
- }
- done:
-
-
- }
- void
- indev_tcp_t_upcall(tcb, avail)
- struct tcb *tcb;
- int16 avail;
- {
- /* ObtainSemaphore(&(INLock));*/
- do_tupcall(tcb, avail);
- /* ReleaseSemaphore(&(INLock)); */
-
- }
-
- void
- indev_s_upcall(tcb, old, new)
- struct tcb *tcb;
- char old, new;
- {
- register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
- char notify = 0;
- extern char *tcpstates[];
- extern char *reasons[];
- extern char *unreach[];
- extern char *exceed[];
-
- /* Can't add a check for unknown connection here, it would loop
- * on a close upcall! We're just careful later on.
- */
-
- if(unit != NULL)
- notify = 1;
-
- switch(new){
- case CLOSE_WAIT:
- if(notify)
- printf("%s\r\n",tcpstates[new]);
- close_tcp(tcb);
- break;
- case CLOSED: /* court adjourned */
- if(notify){
- printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
- if(tcb->reason == NETWORK){
- switch(tcb->type){
- case DEST_UNREACH:
- printf(": %s unreachable",unreach[tcb->code]);
- break;
- case TIME_EXCEED:
- printf(": %s time exceeded",exceed[tcb->code]);
- break;
- }
- }
- printf(")\r\n");
- }
- del_tcp(tcb);
- break;
- default:
- if(notify)
- printf("%s\r\n",tcpstates[new]);
- break;
- }
- fflush(stdout);
-
- }
- #endif
-